#include "ffinclude.h"


/*
    初始化队列

    max_size: 最大存储帧的数量
    keep_last: 是否保留最后一次读取的帧

    return: 0（成功）
*/
int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
{
    if(f->inited){
        return 0;
    }

    int i;
    memset(f, 0, sizeof(FrameQueue));
    f->inited=true;
    if (!(f->mutex = SDL_CreateMutex())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    if (!(f->cond = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    f->pktq = pktq;
    f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
    f->keep_last = !!keep_last;
    for (i = 0; i < f->max_size; i++)
        if (!(f->queue[i].frame = av_frame_alloc()))
            return AVERROR(ENOMEM);
    return 0;
}

/*
    销毁队列，并释放所有缓存的数据
*/
void frame_queue_destory(FrameQueue *f)
{
    if(!f->inited){
        return;
    }
    f->inited=false;

    int i;
    for (i = 0; i < f->max_size; i++) {
        Frame *vp = &f->queue[i];
        frame_queue_unref_item(vp);
        av_frame_free(&vp->frame);
    }
    SDL_DestroyMutex(f->mutex);
    SDL_DestroyCond(f->cond);

    f->mutex=NULL;
    f->cond=NULL;
    f->pktq=NULL;
    f->rindex=0;
    f->windex=0;
    f->size=0;
    f->max_size=0;
    f->keep_last=0;
    f->rindex_shown=0;


}


/*
    返回Frame引用的AVFrame在输入文件中的字节位置
*/
int64_t frame_queue_last_pos(FrameQueue *f)
{
    if(f->inited){
        Frame *fp = &f->queue[f->rindex];
        if (f->rindex_shown && fp->serial == f->pktq->serial)
            return fp->pos;
        else
            return -1;
    }else{
        return -1;
    }
}

/*
    释放Frame引用的AVFrame
*/
void frame_queue_unref_item(Frame *vp)
{
    if(vp){
        av_frame_unref(vp->frame);
        avsubtitle_free(&vp->sub);
    }
}





/*
    从缓冲区中返回一个可写的位置

    注意：调用此函数不会使读取位置偏移

    block：是否阻塞读取
    return: NULL(非阻塞模式下无位置可写，或关联的Packet队列已停止)
*/
Frame *frame_queue_peek_writable(FrameQueue *f, bool block)
{
    if(!f->inited){
        return NULL;
    }

    SDL_LockMutex(f->mutex);
    if(block){
        while (f->size >= f->max_size &&
               !f->pktq->abort_request)
        {
            SDL_CondWait(f->cond, f->mutex);
        }
    }else{
        if (f->size >= f->max_size &&
                !f->pktq->abort_request)
        {

            SDL_UnlockMutex(f->mutex);
            return NULL;
        }
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
        return NULL;

    return &f->queue[f->windex];
}

/*
    从缓冲区所有有效的数据中，返回最早插入的包

    注意：调用此函数不会使读取位置偏移

    block：是否阻塞读取
*/
Frame *frame_queue_peek_readable(FrameQueue *f,bool block)
{
    if(!f->inited){
        return NULL;
    }

    SDL_LockMutex(f->mutex);
    if(block){
        while (f->size - f->rindex_shown <= 0 &&
               !f->pktq->abort_request) {
            SDL_CondWait(f->cond, f->mutex);
        }
    }else{
        if(f->size - f->rindex_shown<=0){
            SDL_UnlockMutex(f->mutex);
            return NULL;
        }
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
        return NULL;

    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}


/*
    更新写索引（+1），配合frame_queue_peek_writable实现元素入列
*/
void frame_queue_push(FrameQueue *f)
{
    if(!f->inited){
        return ;
    }

    if (++f->windex == f->max_size)
        f->windex = 0;
    SDL_LockMutex(f->mutex);
    f->size++;
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

/*
    更新读索引（-1），配合frame_queue_peek_readable实现元素出列。元素出列后
    可通过frame_queue_peek_last获取之前出列的元素。
*/
void frame_queue_next(FrameQueue *f)
{
    if(!f->inited){
        return ;
    }

    if (f->keep_last && !f->rindex_shown) {
        f->rindex_shown = 1;
        return;
    }
    frame_queue_unref_item(&f->queue[f->rindex]);
    if (++f->rindex == f->max_size)
        f->rindex = 0;
    SDL_LockMutex(f->mutex);
    f->size--;
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}


/*
    返回当前帧
*/
Frame *frame_queue_peek_current(FrameQueue *f)
{
    if(!f->inited){
        return NULL;
    }

    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}

/*
    返回当前帧的上一帧
*/
Frame *frame_queue_peek_last(FrameQueue *f)
{
    if(!f->inited){
        return NULL;
    }

    return &f->queue[f->rindex];
}

/*
    返回当前帧的下一帧
*/
Frame *frame_queue_peek_next(FrameQueue *f)
{
    if(!f->inited){
        return NULL;
    }

    return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
}

/*
    唤醒阻塞的peek调用
*/
void frame_queue_signal(FrameQueue *f)
{
    if(!f->inited){
        return ;
    }

    SDL_LockMutex(f->mutex);
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

/*
    返回当前队列剩余帧的数量
*/
int frame_queue_nb_remaining(FrameQueue *f)
{
    if(!f->inited){
        return 0;
    }

    return f->size - f->rindex_shown;
}



/*
    从队列顶端中读取一包数据（最早存入的数据）。数据采用深拷贝模式读取，数据读出
    后将会从队列中删除。

    pkt：存储读出的数据，需要提前new出来
    block：是否采用阻塞模式读取
    serial: 包的序列号
    return: -1（队列停止）,0（无包可取），1（取包成功）
*/
int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
{
    if(!q->inited){
        return -1;
    }

    MyAVPacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);

    for (;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }

        pkt1 = q->first_pkt;
        if (pkt1) {
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
            q->duration -= pkt1->pkt.duration;
            *pkt = pkt1->pkt;
            if (serial)
                *serial = pkt1->serial;
            av_free(pkt1);
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}

/*
    启动队列，只有队列启动后才能接受数据。队列启动时
    会压入一个flush帧，其结果是会清除解码器的缓存
*/
void packet_queue_start(PacketQueue *q,AVPacket* flush_pkt)
{
    if(!q->inited){
        return ;
    }

    SDL_LockMutex(q->mutex);
    q->abort_request = 0;
    q->flush_pkt=flush_pkt;
    packet_queue_put_private(q, flush_pkt);
    SDL_UnlockMutex(q->mutex);
}

/*
    停止队列，队列停止后将不再接受数据。并且所有尝试从队列
    阻塞读取都会立即返回。
*/
void packet_queue_abort(PacketQueue *q)
{
    if(!q->inited){
        return ;
    }

    SDL_LockMutex(q->mutex);

    q->abort_request = 1;

    SDL_CondSignal(q->cond);

    SDL_UnlockMutex(q->mutex);
}

/*
    销毁队列，并清除所有缓存的包
*/
void packet_queue_destroy(PacketQueue *q)
{
    if(!q->inited){
        return ;
    }
    q->inited=false;

    packet_queue_flush(q);

    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);


}

/*
    清空队列所有缓存的数据
*/
void packet_queue_flush(PacketQueue *q)
{
    if(!q->inited){
        return ;
    }

    MyAVPacketList *pkt, *pkt1;

    SDL_LockMutex(q->mutex);
    for (pkt = q->first_pkt; pkt; pkt = pkt1) {
        pkt1 = pkt->next;
        av_packet_unref(&pkt->pkt);
        av_freep(&pkt);
    }
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
    q->duration = 0;
    SDL_UnlockMutex(q->mutex);
}

/*
    初始化队列，并将状态设置为stop
*/
int packet_queue_init(PacketQueue *q)
{
    if(q->inited){
        return 0;
    }

    memset(q, 0, sizeof(PacketQueue));
    q->inited=true;
    q->mutex = SDL_CreateMutex();
    if (!q->mutex) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    q->cond = SDL_CreateCond();
    if (!q->cond) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    q->abort_request = 1;
    return 0;
}

/*
    向队列存入一包空数据，其结果是清除显示的最后一帧画面
*/
int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
{
    if(!q->inited){
        return -1;
    }

    AVPacket pkt1, *pkt = &pkt1;
    av_init_packet(pkt);
    pkt->data = NULL;
    pkt->size = 0;
    pkt->stream_index = stream_index;
    return packet_queue_put(q, pkt);
}

/*
    向队列存入一包数据
*/
int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    if(!q->inited){
        return -1;
    }

    int ret;

    SDL_LockMutex(q->mutex);
    ret = packet_queue_put_private(q, pkt);
    SDL_UnlockMutex(q->mutex);

    if (pkt != q->flush_pkt && ret < 0)
        av_packet_unref(pkt);

    return ret;
}

/*
    向队列存入一包数据。如果存入的是flush帧，则会使serial加1，
    以表示后续取的是新流的数据。

    return: -1（队列停止或内存不足）,0（存入成功）
*/
int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
    if(!q->inited){
        return -1;
    }

    MyAVPacketList *pkt1;

    if (q->abort_request)
        return -1;

    pkt1 = (MyAVPacketList *)av_malloc(sizeof(MyAVPacketList));
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
    if (pkt == q->flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;

    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
    q->size += pkt1->pkt.size + sizeof(*pkt1);
    q->duration += pkt1->pkt.duration;
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
    return 0;
}

/*
    初始化时钟
*/
void init_clock(Clock *c, int *queue_serial)
{
    c->speed = 1.0;
    c->paused = 0;
    c->queue_serial = queue_serial;
    set_clock(c, NAN, -1);
}

/*
    返回时钟c当前的时间
*/
double get_clock(Clock *c)
{
    if (*c->queue_serial != c->serial)
        return NAN;
    if (c->paused) {
        return c->pts;
    } else {
        double time = av_gettime_relative() / 1000000.0;
        return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
    }
}
void sync_clock_to_slave(Clock *c, Clock *slave)
{
    double clock = get_clock(c);
    double slave_clock = get_clock(slave);
    if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
        set_clock(c, slave_clock, slave->serial);
}

/*
    设置时钟的速率
*/
void set_clock_speed(Clock *c, double speed)
{
    set_clock(c, get_clock(c), c->serial);
    c->speed = speed;
}

/*
    设置时钟
*/
void set_clock(Clock *c, double pts, int serial)
{
    double time = av_gettime_relative() / 1000000.0;
    set_clock_at(c, pts, serial, time);
}

/*
    设置时钟
*/
void set_clock_at(Clock *c, double pts, int serial, double time)
{
    c->pts = pts;
    c->last_updated = time;
    c->pts_drift = c->pts - time;
    c->serial = serial;
}

QString avErrorCodeToString(int errCode)
{
    char error_msg[1024];
    av_strerror(errCode, error_msg, sizeof(error_msg));

    return QString(error_msg);
}
